package GoPing

import (
	"fmt"
	"net"
	"strconv"
	"strings"
)

// NetworkScanner 網段掃描器結構體
type NetworkScanner struct {
	Concurrency *Concurrency    // 使用已有的並發框架
	Results     map[string]bool // 掃描結果
	Network     string          // 網段，如 "192.168.1.0/24"
	StartIP     net.IP          // 開始 IP 地址
	EndIP       net.IP          // 結束 IP 地址
	IPList      []string        // 待掃描的 IP 列表
}

// NewNetworkScanner 創建一個新的網段掃描器
// network: 網段表示法，如 "192.168.1.0/24" 或 "192.168.1.1-192.168.1.254"
// 返回一個網段掃描器指針
func NewNetworkScanner(network string) (*NetworkScanner, error) {
	scanner := &NetworkScanner{
		Network: network,
		Results: make(map[string]bool),
	}

	// 解析網段並生成 IP 列表
	ips, err := scanner.parseNetwork()
	if err != nil {
		return nil, err
	}

	// 使用生成的 IP 列表創建並發處理實例
	scanner.IPList = ips
	scanner.Concurrency = NewConcurrency(ips)

	return scanner, nil
}

// parseNetwork 解析網段字符串並生成 IP 列表
// 支持 CIDR 格式（如 192.168.1.0/24）和範圍格式（如 192.168.1.1-192.168.1.254）
func (s *NetworkScanner) parseNetwork() ([]string, error) {
	var ips []string

	// 檢查網段格式
	if strings.Contains(s.Network, "/") {
		// CIDR 格式
		return s.parseCIDR()
	} else if strings.Contains(s.Network, "-") {
		// 範圍格式
		return s.parseRange()
	}

	// 單個 IP 地址
	if net.ParseIP(s.Network) != nil {
		ips = append(ips, s.Network)
		return ips, nil
	}

	return nil, fmt.Errorf("無效的網段格式: %s", s.Network)
}

// parseCIDR 解析 CIDR 格式的網段
func (s *NetworkScanner) parseCIDR() ([]string, error) {
	// 解析 CIDR
	_, ipNet, err := net.ParseCIDR(s.Network)
	if err != nil {
		return nil, fmt.Errorf("無效的 CIDR 格式: %s, %v", s.Network, err)
	}

	// 計算網段中的 IP 地址
	return generateIPsFromCIDR(ipNet)
}

// parseRange 解析範圍格式的網段（如 192.168.1.1-192.168.1.254）
func (s *NetworkScanner) parseRange() ([]string, error) {
	// 分割範圍
	parts := strings.Split(s.Network, "-")
	if len(parts) != 2 {
		return nil, fmt.Errorf("無效的 IP 範圍格式: %s", s.Network)
	}

	// 解析開始和結束 IP
	startIP := net.ParseIP(strings.TrimSpace(parts[0]))
	endIP := net.ParseIP(strings.TrimSpace(parts[1]))

	if startIP == nil || endIP == nil {
		return nil, fmt.Errorf("無效的 IP 地址: %s 或 %s", parts[0], parts[1])
	}

	// 保存開始和結束 IP
	s.StartIP = startIP
	s.EndIP = endIP

	// 生成 IP 範圍內的所有 IP 地址
	return generateIPsFromRange(startIP, endIP)
}

// Start 啟動網段掃描
func (s *NetworkScanner) Start() {
	// 使用並發框架啟動掃描
	s.Concurrency.Start()

	// 掃描完成後複製結果
	for ip, reachable := range s.Concurrency.Result {
		s.Results[ip] = reachable
	}
}

// GetResults 獲取掃描結果
func (s *NetworkScanner) GetResults() map[string]bool {
	return s.Results
}

// GetReachableIPs 獲取可達的 IP 列表
func (s *NetworkScanner) GetReachableIPs() []string {
	var reachable []string
	for ip, isReachable := range s.Results {
		if isReachable {
			reachable = append(reachable, ip)
		}
	}
	return reachable
}

// GetUnreachableIPs 獲取不可達的 IP 列表
func (s *NetworkScanner) GetUnreachableIPs() []string {
	var unreachable []string
	for ip, isReachable := range s.Results {
		if !isReachable {
			unreachable = append(unreachable, ip)
		}
	}
	return unreachable
}

// GetStats 獲取統計信息
func (s *NetworkScanner) GetStats() (total, success, fail int32) {
	return s.Concurrency.Total, s.Concurrency.Success, s.Concurrency.Fail
}

// generateIPsFromCIDR 從 CIDR 格式生成 IP 列表
func generateIPsFromCIDR(ipNet *net.IPNet) ([]string, error) {
	var ips []string

	// 獲取 IP 地址的字節表示
	mask := ipNet.Mask
	networkIP := ipNet.IP.To4()

	if networkIP == nil {
		return nil, fmt.Errorf("僅支持 IPv4 地址")
	}

	// 計算主機部分的大小
	ones, bits := mask.Size()
	hostBits := bits - ones

	// 計算可能的主機地址數量
	numHosts := 1 << uint(hostBits) // 2^hostBits

	// 如果網段過大，可能導致內存問題，設置一個合理的上限
	if numHosts >= 65536 {
		return nil, fmt.Errorf("網段太大 (%d 個主機)，請使用較小的網段", numHosts)
	}

	// 遍歷所有可能的主機地址
	for i := 0; i < numHosts; i++ {
		// 跳過網絡地址（全0）和廣播地址（全1）
		if i == 0 || i == numHosts-1 {
			continue
		}

		// 計算當前 IP
		ip := make(net.IP, len(networkIP))
		copy(ip, networkIP)

		// 將主機地址添加到網絡地址
		hostValue := i
		for j := 3; j >= 0; j-- {
			ip[j] |= byte(hostValue & 0xff)
			hostValue >>= 8
		}

		// 檢查 IP 是否在網段內
		if ipNet.Contains(ip) {
			ips = append(ips, ip.String())
		}
	}

	return ips, nil
}

// generateIPsFromRange 從 IP 範圍生成 IP 列表
func generateIPsFromRange(startIP, endIP net.IP) ([]string, error) {
	var ips []string

	// 轉換為 IPv4
	start := startIP.To4()
	end := endIP.To4()

	if start == nil || end == nil {
		return nil, fmt.Errorf("僅支持 IPv4 地址")
	}

	// 檢查結束 IP 是否大於開始 IP
	if !isLessThanOrEqual(start, end) {
		return nil, fmt.Errorf("開始 IP 必須小於或等於結束 IP")
	}

	// 計算 IP 之間的範圍大小
	size := ipToInt(end) - ipToInt(start) + 1

	// 如果範圍過大，可能導致內存問題，設置一個合理的上限
	if size >= 65536 {
		return nil, fmt.Errorf("IP 範圍太大 (%d 個 IP)，請使用較小的範圍", size)
	}

	// 遍歷 IP 範圍
	current := make([]byte, len(start))
	copy(current, start)

	for {
		// 添加當前 IP
		ips = append(ips, net.IP(current).String())

		// 如果已達到結束 IP，則停止
		if isEqual(current, end) {
			break
		}

		// 增加 IP
		incrementIP(current)
	}

	return ips, nil
}

// isLessThanOrEqual 檢查 IP1 是否小於或等於 IP2
func isLessThanOrEqual(ip1, ip2 net.IP) bool {
	for i := 0; i < len(ip1); i++ {
		if ip1[i] < ip2[i] {
			return true
		}
		if ip1[i] > ip2[i] {
			return false
		}
	}
	return true // 相等
}

// isEqual 檢查兩個 IP 是否相等
func isEqual(ip1, ip2 []byte) bool {
	if len(ip1) != len(ip2) {
		return false
	}
	for i := 0; i < len(ip1); i++ {
		if ip1[i] != ip2[i] {
			return false
		}
	}
	return true
}

// incrementIP 將 IP 地址增加 1
func incrementIP(ip []byte) {
	for i := len(ip) - 1; i >= 0; i-- {
		ip[i]++
		if ip[i] > 0 {
			break
		}
	}
}

// ipToInt 將 IP 轉換為整數
func ipToInt(ip net.IP) int64 {
	ip = ip.To4()
	return int64(ip[0])<<24 | int64(ip[1])<<16 | int64(ip[2])<<8 | int64(ip[3])
}

// ScanNetwork 掃描指定的網段
// network: 網段，如 "192.168.1.0/24" 或 "192.168.1.1-192.168.1.254"
// 返回掃描器對象，以便獲取結果
func ScanNetwork(network string) (*NetworkScanner, error) {
	scanner, err := NewNetworkScanner(network)
	if err != nil {
		return nil, err
	}

	scanner.Start()
	return scanner, nil
}

// ParseIPRange 解析 IP 範圍字符串，生成 IP 列表
// 格式: "192.168.1.1-192.168.1.10" 或 "192.168.1.0/24"
// 用於外部直接調用，生成 IP 列表
func ParseIPRange(ipRange string) ([]string, error) {
	scanner, err := NewNetworkScanner(ipRange)
	if err != nil {
		return nil, err
	}

	return scanner.IPList, nil
}

// IsValidNetwork 檢查網段格式是否有效
func IsValidNetwork(network string) bool {
	// 檢查 CIDR 格式
	if strings.Contains(network, "/") {
		_, _, err := net.ParseCIDR(network)
		return err == nil
	}

	// 檢查範圍格式
	if strings.Contains(network, "-") {
		parts := strings.Split(network, "-")
		if len(parts) != 2 {
			return false
		}

		startIP := net.ParseIP(strings.TrimSpace(parts[0]))
		endIP := net.ParseIP(strings.TrimSpace(parts[1]))

		return startIP != nil && endIP != nil
	}

	// 檢查單個 IP 地址
	return net.ParseIP(network) != nil
}

// ParseSubnet 根據 IP 地址和子網掩碼生成 CIDR 格式
// ip: IP 地址，如 "192.168.1.1"
// mask: 子網掩碼，如 "255.255.255.0" 或 "24"
func ParseSubnet(ip string, mask string) (string, error) {
	// 解析 IP 地址
	ipAddr := net.ParseIP(ip)
	if ipAddr == nil {
		return "", fmt.Errorf("無效的 IP 地址: %s", ip)
	}

	// 將 IP 轉換為 IPv4
	ipv4 := ipAddr.To4()
	if ipv4 == nil {
		return "", fmt.Errorf("僅支持 IPv4 地址")
	}

	// 解析子網掩碼
	var ipMask net.IPMask

	// 檢查掩碼是否為 CIDR 前綴長度（如 "24"）
	if len(mask) <= 2 {
		prefixLen, err := strconv.Atoi(mask)
		if err != nil || prefixLen < 0 || prefixLen > 32 {
			return "", fmt.Errorf("無效的前綴長度: %s", mask)
		}
		ipMask = net.CIDRMask(prefixLen, 32)
	} else {
		// 解析點分十進制掩碼（如 "255.255.255.0"）
		maskAddr := net.ParseIP(mask)
		if maskAddr == nil {
			return "", fmt.Errorf("無效的子網掩碼: %s", mask)
		}
		ipMask = net.IPv4Mask(maskAddr[12], maskAddr[13], maskAddr[14], maskAddr[15])
	}

	// 計算網絡地址
	network := net.IPNet{
		IP:   ipv4.Mask(ipMask),
		Mask: ipMask,
	}

	// 返回 CIDR 格式
	ones, _ := ipMask.Size()
	return fmt.Sprintf("%s/%d", network.IP.String(), ones), nil
}
